using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Framework.Timer
{
    /// <summary>
    /// //对全局提供Update服务
    /// </summary>
    public sealed class GameUpdateMgr : MonoBehaviour
    {
        #region Debug

        [SerializeField] private int UpdateCount;

        [SerializeField] private int FixedUpdateCount;

        [SerializeField] private int LaterUpdateCount;

        [SerializeField] private int CoroutineCount;

        [SerializeField] private int TimerCount;

        #endregion

        /// <summary>
        /// update类型
        /// </summary>
        public enum UpdaterType
        {
            Update,
            FixedUpdate,
            LaterUpdate,
            Coroutine
        }

        private static bool mIsInit = false;//初始化是否完成
        private static GameUpdateMgr _instance;

        private const int _DEFAULT_LENGTH = 1;
        /// <summary>
        /// 调用时创建新组件绑定
        /// </summary>
        public static GameUpdateMgr Instance
        {
            get
            {
                if (_instance == null && !mIsInit)
                {

                    var objs = FindObjectsOfType<GameUpdateMgr>();
                    for (int i = 0; i < objs.Length; i++)
                    {
                        Destroy(objs[i]);
                    }

                    _instance = new GameObject().AddComponent<GameUpdateMgr>();
                    _instance.name = "[GameUpdater]";
                    DontDestroyOnLoad(_instance);
                    _instance.Init();
                    mIsInit = true;
                }

                return _instance;
            }
            private set { _instance = value; }
        }

        private List<Action> _UpdateList;
        private List<Action> _FixedUpdateList;
        private List<Action> _LaterUpdateList;
        private List<Action> _CoroutineList;
        private List<TimeHandler> _TimeHandlers;

        private void Init()
        {
            this._UpdateList = new List<Action>(_DEFAULT_LENGTH);
            this._FixedUpdateList = new List<Action>(_DEFAULT_LENGTH);
            this._LaterUpdateList = new List<Action>(_DEFAULT_LENGTH);
            this._CoroutineList = new List<Action>(_DEFAULT_LENGTH);
            this._TimeHandlers = new List<TimeHandler>(_DEFAULT_LENGTH);
            this.StartCoroutine(this.UpdateCoroutine());
            this.StartCoroutine(this.UpdateTimer());
        }

        private void _InvokeUpdate(List<Action> list)
        {
            for (int i = list.Count - 1; i >= 0; i--)
            {
                //在遍历时可能会出现外部操作list导致Count改变
                if (i >= list.Count)
                    continue;
                if (list[i] == null)
                {
                    list.RemoveAt(i);
                }
                else
                {
                    list[i].Invoke();
                }
            }
        }
        /// <summary>
        /// 当前调用update方法的数量
        /// </summary>
        private void _UpdateCount()
        {
            this.UpdateCount = this._UpdateList.Count;
            this.FixedUpdateCount = this._FixedUpdateList.Count;
            this.LaterUpdateCount = this._LaterUpdateList.Count;
            this.CoroutineCount = this._CoroutineList.Count;
            this.TimerCount = this._TimeHandlers.Count;
        }

        #region Updater方法入口

        private void Update() => this._InvokeUpdate(this._UpdateList);
        private void FixedUpdate() => this._InvokeUpdate(this._FixedUpdateList);
        private void LateUpdate() => this._InvokeUpdate(this._LaterUpdateList);
        /// <summary>
        /// 一般携程调用入口
        /// </summary>
        /// <returns></returns>
        private IEnumerator UpdateCoroutine()
        {
            while (true)
            {
                this._InvokeUpdate(this._CoroutineList);
                yield return null;
            }
        }
        /// <summary>
        /// 计时器入口
        /// </summary>
        /// <returns></returns>
        private IEnumerator UpdateTimer()
        {
            while (true)
            {
#if UNITY_EDITOR
                this.TimerCount = this._TimeHandlers.Count;
#endif
                for (int i = this._TimeHandlers.Count - 1; i >= 0; i--)
                {
                    var timeHandler = this._TimeHandlers[i];
                    //如果计时器为空|完成|被删除，则移除该计时器
                    if (timeHandler == null || timeHandler.IsDone || timeHandler._isKill)
                    {
                        this._TimeHandlers.RemoveAt(i);
                    }
                    else
                    {
                        timeHandler.Update();
                    }
                }

                yield return null;
            }
        }

        #endregion

        #region 一般updater接口方法


        public void AddUpdater(Action updater, UpdaterType updaterType = UpdaterType.Update)
        {
            
            switch (updaterType)
            {
                case UpdaterType.Update:

                    this._UpdateList.Add(updater);
                    break;
                case UpdaterType.FixedUpdate:
                    this._FixedUpdateList.Add(updater);
                    break;
                case UpdaterType.LaterUpdate:
                    this._LaterUpdateList.Add(updater);
                    break;
                case UpdaterType.Coroutine:
                    this._CoroutineList.Add(updater);
                    break;
            }
#if UNITY_EDITOR
            this._UpdateCount();
#endif
        }

        public void RemoveUpdater(Action updater, UpdaterType updaterType = UpdaterType.Update)
        {
            switch (updaterType)
            {
                case UpdaterType.Update:
                    this._UpdateList.Remove(updater);
                    break;
                case UpdaterType.FixedUpdate:
                    this._FixedUpdateList.Remove(updater);
                    break;
                case UpdaterType.LaterUpdate:
                    this._LaterUpdateList.Add(updater);
                    break;
                case UpdaterType.Coroutine:
                    this._CoroutineList.Remove(updater);
                    break;
            }
#if UNITY_EDITOR
            this._UpdateCount();
#endif
        }

        #endregion


        #region TimeHadler接口方法


        /// <summary>
        /// 创建计时器
        /// </summary>
        /// <param name="delay">延时时间</param>
        /// <param name="callback">回调方法</param>
        /// <param name="update">计时时方法</param>
        /// <returns></returns>
        public TimeHandler CreateTimer(float delay, Action callback, Action<float> update = null)
        {
            //如果时间小于等于0，直接调用
            if (delay <= 0)
            {
                callback.Invoke();
                return null;
            }

            var timer = new TimeHandler(delay, callback, update);
            this._TimeHandlers.Add(timer);
            return timer;
        }

        public TimeHandler CreateTimer(GameObject gameObject, float delay, Action callback, Action<float> update = null)
        {
            if (delay <= 0)
            {
                callback.Invoke();
                return null;
            }

            var timer = new TimeHandler(gameObject, delay, callback, update);
            this._TimeHandlers.Add(timer);
            return timer;
        }


        public TimeHandler CreateFrameTimer(int frame, Action callback, Action<float> update = null)
        {
            var timer = new TimeHandler(frame/20f, true, callback, update);
            if (frame <= 0)
            {
                timer._isKill = true;
                callback.Invoke();
                return timer;
            }
            this._TimeHandlers.Add(timer);
            return timer;
        }


        /// <summary>
        /// 创建框架计时器（罗秋水自制框架:0.001s后调用既马上调用一次）
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        public TimeHandler CreateOneFrameTimer(Action callback, Action<float> update = null)
        {
            return this.CreateTimer(0.001f, callback, update);
        }
        /// <summary>
        /// 暂停计时器列表
        /// </summary>
        /// <param name="b"></param>
        public void PauseTimeHandlerList(bool b)
        {
            foreach (var item in _TimeHandlers)
            {
                item.Pause(b);
            }
        }
     
        
        #endregion



    }

}